package cn.yemuysy.code.check.service.impl;

import cn.yemuysy.code.check.model.InfringingWord;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 表示Trie（字典树）数据结构中的节点，用于高效的字符串匹配。
 * 此类是Aho-Corasick算法实现的核心组件，每个节点可以：
 * <ul>
 *   <li>存储子节点（通过字符映射）</li>
 *   <li>标记单词结尾并关联侵权词信息</li>
 *   <li>维护失败链接（failure links）用于模式匹配失败时的状态转移</li>
 *   <li>维护输出链接（output links）用于快速识别所有匹配的模式</li>
 * </ul>
 * 节点之间的这些链接共同构成了一个高效的自动机，能够在线性时间内同时匹配多个模式。
 */
public class TrieNode {
    /**
     * 子节点，按字符映射
     */
    private final Map<Character, TrieNode> children = new HashMap<>();

    /**
     * 节点的唯一标识符，用于可视化和调试目的。
     * 默认值为-1，表示尚未分配ID。
     */
    @Getter
    @Setter
    private int nodeId = -1;
    /**
     * 标志表示该节点是否代表一个单词的结尾
     */
    private boolean isEndOfWord = false;

    /**
     * 如果该节点是单词结尾，则存储侵权词信息
     */
    @Getter
    private InfringingWord infringingWord = null;

    /**
     * 失败链接 - Aho-Corasick算法中的关键部分
     * 当当前字符不匹配时，指向应该转移到的下一个节点
     */
    @Getter
    @Setter
    private TrieNode failureLink = null;

    /**
     * 输出链接 - 存储所有在当前节点结束的模式
     * 用于Aho-Corasick算法中快速识别所有匹配
     */
    @Getter
    private final List<TrieNode> outputLinks = new ArrayList<>();

    /**
     * 获取字符对应的子节点，如果不存在则创建
     *
     * @param c 字符
     * @return 子节点
     */
    public TrieNode getOrCreateChild(char c) {
        return children.computeIfAbsent(c, k -> new TrieNode());
    }

    /**
     * 获取字符对应的子节点
     *
     * @param c 字符
     * @return 子节点，如果不存在则返回null
     */
    public TrieNode getChild(char c) {
        return children.get(c);
    }

    /**
     * 检查该节点是否有给定字符的子节点
     *
     * @param c 字符
     * @return 如果存在该字符的子节点则返回true
     */
    public boolean hasChild(char c) {
        return children.containsKey(c);
    }

    /**
     * 将该节点标记为单词的结尾
     *
     * @param word 侵权词信息
     */
    public void setEndOfWord(InfringingWord word) {
        this.isEndOfWord = true;
        this.infringingWord = word;
    }

    /**
     * 检查该节点是否代表一个单词的结尾
     *
     * @return 如果该节点是单词结尾则返回true
     */
    public boolean isEndOfWord() {
        return isEndOfWord;
    }

    /**
     * 添加输出链接到另一个节点
     * 在Aho-Corasick算法中用于记录所有可能的匹配
     *
     * @param node 要链接的节点
     */
    public void addOutputLink(TrieNode node) {
        if (node != null) {
            outputLinks.add(node);
        }
    }

    /**
     * 批量添加输出链接。
     * 输出链接是Aho-Corasick算法的关键部分，它们允许在到达某个节点时
     * 快速识别所有可能的匹配，包括那些通过失败链接可达的模式。
     * 此方法通常在构建失败链接时使用，用于继承失败链接节点的所有输出链接，
     * 确保不会漏掉任何可能的匹配。
     *
     * @param nodes 要链接的节点列表，通常是另一个节点的输出链接集合
     */
    public void addOutputLinks(List<TrieNode> nodes) {
        if (nodes != null) {
            outputLinks.addAll(nodes);
        }
    }

    /**
     * 获取所有子节点。
     * 此方法提供对节点所有子节点的直接访问，主要用于：
     * <ul>
     *   <li>遍历Trie树结构（如在构建失败链接时）</li>
     *   <li>合并Trie树（将一个Trie的节点复制到另一个）</li>
     *   <li>可视化Trie树（生成图形表示）</li>
     * </ul>
     * 返回的Map是内部存储的直接引用，调用者应避免修改其内容。
     *
     * @return 包含所有子节点的Map，键为字符，值为对应的TrieNode
     */
    public Map<Character, TrieNode> getChildren() {
        return children;
    }

}
